package org.bsc.mgwt.client.mvp.experimental;

import java.util.LinkedHashSet;
import java.util.Set;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.event.shared.ResettableEventBus;
import com.google.gwt.event.shared.UmbrellaException;
import com.google.gwt.place.shared.Place;
import com.google.gwt.user.client.ui.AcceptsOneWidget;

/**
 * 
 * @author softphone
 *
 */
public class ActivityMapperManager {
	/**
	 * 
	 */
	private static final Activity NULL_ACTIVITY = new AbstractActivity() {
		@Override
		public void start(AcceptsOneWidget panel, com.google.gwt.event.shared.EventBus eventBus) {
			panel.setWidget(null);

		}
	};

	private ActivityMapper mainActivityMapper ;
	
	private final ResettableEventBus stopperedEventBus;
	private Activity currentActivity = NULL_ACTIVITY;
	private boolean startingNext = false;
	//private Place currentPlace;

	private final AcceptsOneWidget container;
	
	/**
	 * 
	 */
	public ActivityMapperManager( AcceptsOneWidget panel) {
		this.container = panel;
		com.google.web.bindery.event.shared.EventBus eventBus = 
				new com.google.web.bindery.event.shared.SimpleEventBus();

		this.stopperedEventBus = new ResettableEventBus(eventBus);
	}
	
	/**
	 * 
	 * @param mainActivityMapper
	 * @param mainAnimationMapper
	 */
	public final void init( ActivityMapper mainActivityMapper, Place startPlace ) {
 		
		if( mainActivityMapper == null ) throw new IllegalArgumentException("mainActivityMapper is null!");

		this.mainActivityMapper = mainActivityMapper;
		
		if( startPlace!=null )
			goTo( startPlace );
	}
	
	/**
	 * 
	 * @param newPlace
	 */
	public final void goTo(Place newPlace) {

		Activity nextActivity = mainActivityMapper.getActivity(newPlace); // getNextActivity(event)

		Throwable caughtOnStop = null;
		Throwable caughtOnStart = null;

		if (nextActivity == null) {
			nextActivity = NULL_ACTIVITY;
		}

		if (currentActivity.equals(nextActivity)) {
			return;
		}

		// TODO manages activity.mayStop
		
		if (startingNext) {
			// The place changed again before the new current activity showed
			// its
			// widget
			currentActivity.onCancel();
			currentActivity = NULL_ACTIVITY;
			startingNext = false;
		} else {

			/*
			 * Kill off the activity's handlers, so it doesn't have to worry
			 * about them accidentally firing as a side effect of its tear down
			 */
			stopperedEventBus.removeHandlers();

			try {
				currentActivity.onStop();
			} catch (Throwable t) {
				caughtOnStop = t;
			} finally {
				/*
				 * And kill them off again in case it was naughty and added new
				 * ones during onstop
				 */
				stopperedEventBus.removeHandlers();
			}
		}

		currentActivity = nextActivity;
		//currentPlace = event.getNewPlace();

		startingNext = true;

		/*
		 * Now start the thing. Wrap the actual display with a per-call instance
		 * that protects the display from canceled or stopped activities, and
		 * which maintains our startingNext state.
		 */
		try {
			// currentActivity.start(new ProtectedDisplay(currentActivity), stopperedEventBus);
			currentActivity.start(container, stopperedEventBus);

		} catch (Throwable t) {
			caughtOnStart = t;
		}

		if (caughtOnStart != null || caughtOnStop != null) {
			Set<Throwable> causes = new LinkedHashSet<Throwable>();
			if (caughtOnStop != null) {
				causes.add(caughtOnStop);
			}
			if (caughtOnStart != null) {
				causes.add(caughtOnStart);
			}

			throw new UmbrellaException(causes);
		}

		/*
		 * if (animation != null) { // animate animate(animation);
		 * 
		 * }
		 */

	}

	
}
